﻿Imports System.Net.Sockets
Imports System.Net

Namespace UDPBroadcast

    Public Class Server
        Implements IDisposable

        Private m_Server As UdpClient
        Private m_port As Integer = 65432
        Private m_IsStarting As Boolean = False
        Private m_BroadCastAddress As IPAddress = IPAddress.Parse("224.224.224.224")
        Private m_OnDataReceiveCallBack As New AsyncCallback(AddressOf Me.OnDataReceive)

        Public Event DataReceive(ByVal sender As Object, ByVal e As ServerDataReceiveEventArgs)
        Public Event [Error](ByVal sender As Object, ByVal e As ServerErrorEventArgs)

        Public ReadOnly Property Port() As Integer
            Get
                Return Me.m_port
            End Get
        End Property

        Public ReadOnly Property BroadcastAddress() As IPAddress
            Get
                Return Me.m_BroadCastAddress
            End Get
        End Property

        Public ReadOnly Property IsStarting() As Boolean
            Get
                Return Me.m_IsStarting
            End Get
        End Property

        Public Sub New()
            Me.m_IsStarting = False
            Me.m_Server = New UdpClient(Port, AddressFamily.InterNetwork)
        End Sub

        Public Sub New(ByVal p As Integer, ByVal remoteAddr As String)
            Try
                Me.m_IsStarting = False
                Me.m_port = p
                Me.m_BroadCastAddress = IPAddress.Parse(remoteAddr)
                Me.m_Server = New UdpClient(Me.m_port, AddressFamily.InterNetwork)
            Catch ex As Exception
                Throw ex
            End Try
        End Sub

        Public Sub Start()
            If Me.m_IsStarting Then
                Return
            End If
            Me.m_Server.JoinMulticastGroup(Me.m_BroadCastAddress)
            Me.m_Server.BeginReceive(Me.m_OnDataReceiveCallBack, Me.m_Server)
            Me.m_IsStarting = True
        End Sub

        Public Sub [Stop]()
            If Not IsStarting Then
                Return
            End If
            Me.m_IsStarting = False
            Me.m_Server.DropMulticastGroup(Me.m_BroadCastAddress)
            Me.m_Server.Close()
        End Sub

        Private Sub OnDataReceive([async] As IAsyncResult)
            If Not Me.m_IsStarting Then
                Return
            End If
            Dim server As UdpClient = Nothing
            Try
                server = DirectCast([async].AsyncState, UdpClient)
                Dim remoteEP As New IPEndPoint(IPAddress.Any, 0)
                Dim buffer As Byte() = server.EndReceive([async], remoteEP)
                RaiseEvent DataReceive(server, New ServerDataReceiveEventArgs(remoteEP, buffer))
            Catch ex As ObjectDisposedException
                server = Nothing
            Catch ex As Exception
                RaiseEvent Error(Me, New ServerErrorEventArgs(ex))
            Finally
                If Me.IsStarting AndAlso server IsNot Nothing Then
                    server.BeginReceive(AddressOf Me.OnDataReceive, server)
                End If
            End Try
        End Sub

#Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: dispose managed state (managed objects).
                    Me.Stop()
                End If
                ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
                ' TODO: set large fields to null.
                Me.m_Server = Nothing
            End If
            Me.disposedValue = True
        End Sub

        ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
        Protected Overrides Sub Finalize()
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(False)
            MyBase.Finalize()
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class

End Namespace